package org.example.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.entity.Permissions;
import org.example.entity.Users;

import org.example.filter.TokenFilter;
import org.example.models.LoginUser;
import org.example.models.R;
import org.example.service.PermissionsService;
import org.example.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * 配置类：String安全配置
 */
@Configuration
public class SecurityConfig {

    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    UsersService usersService;

    @Autowired
    PermissionsService permissionsService;

    @Autowired
    TokenFilter tokenFilter;

    ObjectMapper objectMapper= new ObjectMapper();

    /**
     * 配置用户信息
     * @return
     */
    @Bean
    public UserDetailsService userDetailsService() {
//        InMemoryUserDetailsManager manager =new InMemoryUserDetailsManager();
//        UserDetails user1 = User
//                .withUsername("admin")
//                .password("{noop}admin")
//                .authorities("user:get-user","user:delete").build();
//
//        UserDetails user2 = User
//                .withUsername("admin1")
//                .password("{noop}admin1")
//                .authorities("user:update-user").build();
//        manager.createUser(user1);
//        manager.createUser(user2);

        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                QueryWrapper<Users> wrapper = new QueryWrapper<>();
                wrapper.lambda().eq(Users::getUsername,username);
                Users users = usersService.getOne(wrapper);
                if(users==null){
                    throw new BadCredentialsException("用户名不存在");
                }
                List<Permissions> permissions = permissionsService.getPermissions(users.getId());
                LoginUser loginUser = new LoginUser(users,permissions);
                return loginUser;
            }
        };
    }

    /**
     * 配置安全过滤器链
     * spring security核心配置
     * @param chain
     * @return
     * @throws Exception
     */
  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http)
          throws Exception {
      //spring security防伪链
      http.csrf().disable();//禁用csrf
      http.formLogin()
//              .loginPage("/login2")//登录页面
              .loginProcessingUrl("/login2")//登录请求路径
              .usernameParameter("username")//用户名参数
              .passwordParameter("password")//密码参数
              .successHandler(authenticationSuccessHandler)
              .failureHandler(authenticationFailureHandler)
//              .successForwardUrl("/")
//              .defaultSuccessUrl("/")
              .permitAll()//上面两个地址不要进行登录和权限验证
      ;

      //设置security授权提示信息
      http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
          @Override
          public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
              response.setCharacterEncoding("utf-8");
              response.setContentType(MediaType.APPLICATION_JSON_VALUE);
              R<Object> error = R.error(403, "用户验证失败，请重新登录");
              String json = objectMapper.writeValueAsString(error);
              response.getWriter().print(json);
          }
      });
      http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
          @Override
          public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
              //设置用户没有权限时的提示
              response.setCharacterEncoding("utf-8");
              response.setContentType(MediaType.APPLICATION_JSON_VALUE);
              R<Object> error = R.error(403, "用户没有权限");
              String json = objectMapper.writeValueAsString(error);
              response.getWriter().print(json);
          }
      });

      http.authorizeHttpRequests().mvcMatchers("/index").permitAll();
//      http.sessionManagement().sessionConcurrency(SessionCreationPolicy.NEVER);
      //设置需要单独进行验证的权限地址
      for (Permissions permissions : permissionsService.list()) {
          http.authorizeHttpRequests()
              .mvcMatchers(permissions.getUrl())
              .hasAuthority(permissions.getPerm());
      }


//      http.authorizeHttpRequests()
//              .antMatchers("/user/get-user")
//              .hasAuthority("user:get-user");
//      http.authorizeHttpRequests()
//              .antMatchers("/user/delete")
//              .hasAuthority("user:delete");
//      http.authorizeHttpRequests()
//              .antMatchers("/user/update-user")
//              .hasAuthority("user:update-user");
      //所有地址都需要登录才能访问
      http.authorizeHttpRequests().anyRequest().authenticated();
      //修改security校验顺序
      http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
      return http.build();
  }

  @Bean
  public BCryptPasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
  }

     public static void main(String[] args) {
        //$2a$10$GS/WEhYfHk2oKHgR3NI/huIJR2crMqlaUDxv6eFIR14iUU/ttNJ36
        String a= "$2a$10$6YBZtvJOGHn3yic/kwUV3uBBORQzM1oUWSb42.DcQBdLkUrwVx13W";
        String encode = new BCryptPasswordEncoder().encode("123456");
        System.out.println(encode);
//        boolean matches = new BCryptPasswordEncoder().matches("123456", a);
//        System.out.println(matches);
    }
}
